//movietech.cc

#include "movietech.h"
#include "cineplex.h"

MovieTech::MovieTech(char* name)
{
	myName = name;
	msgList = new MsgList();
	myThread = new Thread(myName);
	msgLock = new Lock(myName);
	sleepCon = new Condition(myName);
	numTakersReplyNeeded=0;
	status="Idle";
}

MovieTech::~MovieTech()
{

}

void
MovieTech::Start()
{
	printf("Starting MovieTech %s...\n", myName);
	if(getCineplex()->runSchedulers) Scheduler();
}

void
MovieTech::SendMessage(char* name, int argc, ...)
{
	msgLock->Acquire();
	
	IterList* args = new IterList();
	va_list vali;
	va_start(vali, argc);
	
	for ( int i = 0; i < argc; i++ )        
    {
        args->Append(va_arg ( vali, void* )); 
    }
	va_end(vali);
	
	msgList->Append(name, args);
	sleepCon->Signal(msgLock);
	
	msgLock->Release();
}

void
MovieTech::SendMessage(char* name, IterList* args)
{
	msgLock->Acquire();
	
	msgList->Append(name, args);
	sleepCon->Signal(msgLock);
	
	msgLock->Release();
}

void
MovieTech::Scheduler()
{
	bool runScheduler = getCineplex()->runSchedulers;
	do
	{
		//printf("%s running Scheduler...\n",myName);
	
		msgLock->Acquire();
		IterList* msg;
		if(!strcmp(status,"Idle"))
		{
			if(msgList->Find("StartMovie"))
			{
				msgLock->Release();
				CheckWithLobby();
				continue;
			}
		}
		else if(!strcmp(status,"WaitingForLobby"))
		{
			if(msgList->Find("LobbyEmpty"))
			{
				AskTakerAboutLine();
				msgLock->Release();
				continue;
			}
		}
		else if(!strcmp(status,"WaitingForTakers"))
		{
			if(msgList->Find("LineIsEmpty"))
			{
				TakerIsGood();
				msgLock->Release();
				continue;
			}
		}
		else if(!strcmp(status,"StartingMovie"))
		{
			PlayMovie();
			msgLock->Release();
			continue;
		}
		else if(!strcmp(status,"MovieOver"))
		{
			EndMovie();
			msgLock->Release();
			continue;
		}
		//printf("%s is sleeping...\n",myName);
		msgLock->Release();
		sleepCon->Wait(msgLock);
	} while(runScheduler);
}

void
MovieTech::CheckWithLobby()
{
	//make sure at least one person has entered before seeing if everyone has
	while(getCineplex()->theater->seatsFilled == 0)
	{
		//getCineplex()->waitNotEmpty->Wait(msgLock);//getCineplex()->theater->seatingLock);
		//printf("%s has awoken\n",myName);
		if(getCineplex()->customersRunning!=0)
		{
			currentThread->Yield();
		}
		else
		{
			return;
		}
	}
	printf("asking if lobby is idle\n");
	getCineplex()->lobby->SendMessage("AreYouIdle",1,this);
	status="WaitingForLobby";
}

void
MovieTech::AskTakerAboutLine()
{
	printf("asking takers about lines\n");
	int i=0;
	TicketTaker* taker=(TicketTaker *)getCineplex()->ticketTakers->Get(i);
	while(taker)
	{
		taker->SendMessage("IsYourLineEmpty",1,this);
		i++;
		taker=(TicketTaker *)getCineplex()->ticketTakers->Get(i);
	}
	numTakersReplyNeeded=getCineplex()->ticketTakers->getSize();
	status="WaitingForTakers";
}

void
MovieTech::TakerIsGood()
{
	numTakersReplyNeeded--;
	//printf("%s sees a TT is clear\n",myName);
	if(numTakersReplyNeeded<=0)
	{
		status="StartingMovie";
	}
}

void
MovieTech::PlayMovie()
{
	printf("The MovieTechnician has started the movie.\n");
	getCineplex()->theater->movieStarted=true;
	getCineplex()->letPeopleIn = 0;
	int movieLength=200+getRandPercent();
	for(int i=0;i<movieLength;i++)
	{
		//currentThread->Yield();
	}
	status="MovieOver";
}

void
MovieTech::EndMovie()
{
	printf("The MovieTechnician has ended the movie.\n");
	
	//printf("Seats still filled: %d\n",getCineplex()->theater->seatsFilled);
	//printf("%s acquiring seating lock\n", myName);
	getCineplex()->theater->seatingLock->Acquire();
	//printf("%s acquired seating lock\n", myName);
	/*for(int i=0;i<NUM_ROWS;i++)
	{
		for(int j=0;j<NUM_COLS;j++)
		{
			if((Customer *)getCineplex()->theater->seating[i*NUM_COLS+j])
			{
				printf("x");
			}
			else
			{
				printf("o");
			}
		}
		printf("\n");
	}
	printf("\n");
	printf("\n");*/
	for(int i=0;i<getCineplex()->theater->totalSeats;i++)
	{
		Customer* cust=(Customer *)getCineplex()->theater->seating[i];
		if(cust)
		{
			cust->SendMessage("MovieIsDone",0);
			getCineplex()->theater->seating[i]=NULL;
		}
	}
	getCineplex()->theater->seatingLock->Release();
	printf("The MovieTechnician has told all customers to leave the theater room.\n");
	
	/*printf("Seats still filled: %d\n",getCineplex()->theater->seatsFilled);
	for(int i=0;i<NUM_ROWS;i++)
	{
		for(int j=0;j<NUM_COLS;j++)
		{
			if((Customer *)getCineplex()->theater->seating[i*NUM_COLS+j])
			{
				printf("x");
			}
			else
			{
				printf("o");
			}
		}
		printf("\n");
	}
	printf("\n");
	printf("\n");*/
	getCineplex()->theater->movieStarted=false;
	getCineplex()->manager->SendMessage("MovieOver",0);
	status="Idle";
}
